package com.itheima.springbootwebtlias.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.springbootwebtlias.anno.LogOperation;
import com.itheima.springbootwebtlias.anno.MyLog;
import com.itheima.springbootwebtlias.exception.PasswordErrorException;
import com.itheima.springbootwebtlias.exception.UsernameNotExistException;
import com.itheima.springbootwebtlias.mapper.EmpExprMapper;
import com.itheima.springbootwebtlias.mapper.EmpMapper;
import com.itheima.springbootwebtlias.pojo.*;
import com.itheima.springbootwebtlias.service.EmpLogService;
import com.itheima.springbootwebtlias.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.FileNotFoundException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper; //操作员工表的持久层对象

    @Autowired
    private EmpExprMapper empExprMapper;  // 操作工作记录的持久层对象

    @Autowired
    private EmpLogService empLogService;  // 操作日志的业务层对象

    //分页 + 条件查询
    @Override
    public PageResult page(EmpQueryParam queryParam) {
        /*// 1. 查询指定页的数据: select * from emp where 条件 limit ?, ?
        // 计算起始位置
        int start = (queryParam.getPage() - 1) * queryParam.getPageSize();
        queryParam.setPage(start); // 将页码修改为起始位置
        List<Emp> empList = empMapper.selectPage(queryParam);

        // 2. 查询总记录数: select count(*) from emp
        Long count = empMapper.count(queryParam);*/
        //----------------------------------------------

        // 1. 使用分页插件实现分页查询
        // 1.1 应用/设置分页条件             页码                  条数
        PageHelper.startPage(queryParam.getPage(), queryParam.getPageSize());

        // 1.2 调用被分页插件增强的持久层方法
        Page<Emp> page = (Page<Emp>) empMapper.selectByCondition(queryParam);

        // 1.3 从分页插件增强方法的返回结果中，获取数据并封装到PageResult返回
        PageResult pageResult = new PageResult(page.getTotal(), page.getResult());

        return pageResult;
    }

    // 添加员工
    @LogOperation
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(Emp emp) throws FileNotFoundException {
        try {
            // 1. 调用持久层Mapper，向员工表中添加员工信息
            // 补充基础数据
            emp.setCreateTime(LocalDateTime.now());
            emp.setUpdateTime(LocalDateTime.now());
            empMapper.insert(emp);  //mybatis框架，设置主键返回

            //演示：编译期异常
            /*if(true){
                throw new FileNotFoundException();
            }*/

            // 2. 如果有工作经历信息
            // 调用持久层Mapper，向工作经历列表表中添加工作经历信息
            List<EmpExpr> exprList = emp.getExprList();
            if (exprList != null && exprList.size() > 0) {
                //2.1设置当前员工经历所属的员工信息
                exprList.stream().forEach(ex -> ex.setEmpId(emp.getId()));


                //2.2调用持久层Mapper，向工作经历列表表中添加工作经历信息
                // 方式一：循环添加，交互多，性能低
                /*for (EmpExpr empExpr : exprList) {
                    empExprMapper.insert(empExpr);
                }*/
                // 方式二：批量操作，交互少，性能高
                empExprMapper.insertBatch(exprList); // insert values(), (), (), ()
            }
        } finally {
            //3.记录操作日志
            EmpLog empLog = new EmpLog(emp.getId(), LocalDateTime.now(), "添加员工:" + emp.getName());
            empLogService.insertLog(empLog);
        }
    }

    // 批量删除员工
    @LogOperation
    @Transactional // 使用事务注解
    @Override
    @MyLog
    public void removeBatch(List<Integer> ids) {
        // 1. 调用持久层EmpMapper，批量删除员工信息
        //delete from emp where id in (?, ?, ?, ?, ?)
        empMapper.deleteBatchById(ids);

        // 2. 调用持久层EmpExprMapper，删除员工对应的工作经历信息
        //delete from emp_expr where emp_id in (?, ?, ?, ?, ?)
        empExprMapper.deleteBatchByEmpIds(ids);
    }

    // 根据id查询员工信息
    @Override
    public Emp queryById(Integer id) {

        //方案一：两次单表查询
        // 1. 调用持久层EmpMapper，根据id查询员工信息
        Emp emp = empMapper.selectById(id);

        // 2. 调用持久层EmpExprMapper，根据员工id查询员工对应的工作经历信息
        List<EmpExpr> exprList = empExprMapper.selectByEmpId(id); //单表

        // 3. 封装到Emp返回
        emp.setExprList(exprList);

        //方案二：一次多表查询（数据量大，性能低）
        //Emp emp = empMapper.selectByIdAndExprs(id);

        return emp;
    }

    // 修改员工信息
    @LogOperation
    @Override
    public void update(Emp emp) {
        //1.调用持久层EmpMapper，修改员工信息
        emp.setUpdateTime(LocalDateTime.now()); //更新同步时间
        empMapper.update(emp);

        // 2.调用持久层EmpExprMapper，更新员工对应的工作经历信息
        // 2.1 删除员工对应的所有工作经历信息
        List<Integer> ids = new ArrayList<>();
        ids.add(emp.getId());
        empExprMapper.deleteBatchByEmpIds(ids);

        // 2.2 批量添加员工对应新的工作经历信息
        if (emp.getExprList() != null && emp.getExprList().size() > 0) {
            // 设置新增的所属员工信息
            emp.getExprList().stream().forEach(ex -> ex.setEmpId(emp.getId()));

            empExprMapper.insertBatch(emp.getExprList());
        }

    }

    // 查询所有员工
    @Override
    public List<Emp> queryAll() {
        List<Emp> empList = empMapper.queryAll();
        return empList;
    }

    // 员工登录
    @Override
    public Emp checkLogin(Emp emp) {
        // 1. 调用持久层EmpMapper，根据用户名查询员工信息
        Emp resultEmp = empMapper.selectByUsername(emp.getUsername());

        // 2. 判断员工是否存在，如果不存在，账户不存在（登录失败）
        if(resultEmp == null){
            throw new UsernameNotExistException("亲，睁大你的大眼睛，账户不存在！");
        }

        // 3. 如果存在，比较密码，如果不匹配，密码错误（登录失败）
        if(!Objects.equals(resultEmp.getPassword(), emp.getPassword())){
            throw new PasswordErrorException("亲，睁大你的大眼睛，密码不一致！");
        }

        // 4. 登录成功，返回员工信息
        return resultEmp;
    }



    /*
       spring框架提供：声明式事务，只需要添加注解即可进行事务控制管理
       //底层：动态代理
       //1.程序启动，spring框架扫描所有类中的所有方法
       //2.判断方法上是否添加了@Transactional注解
       //3.使用动态代理模式，创建当前类的代理对象，并将代理对象返回给spring容器管理，替换原来对象
       empServiceImplProxy.add(){
           try{
               //开启事务
               method.invoke(); //add()
               //提交事务
           }catch(){
               //回滚事务
           }
       }
     */
}
